Skip to main content

Providers

Providers are the data sources available for injection. Each provider exposes different fields you can access using dot-notation paths.


chat

Access fields from the current chat object.

%chat:fieldName%
%chat:nested.field.path%

Common fields

PathDescriptionExample output
chat:titleCustomer's WhatsApp display name"John Doe"
chat:channelInfo.idCustomer's phone number"972521234567"
chat:channelInfo.accountIdBusiness WhatsApp number"972586640430"
chat:_idTexter chat ID"64de3b15398a8e09c47a9f62"
chat:labelsLabels applied to the chat["urgent", "billing"]
chat:departmentIdAssigned department"customer_service"
chat:statusChat status (0=bot, 1=pending, 2=taken, 3=resolved, 4=bulk)0
chat:phoneCustomer phone (shorthand)"972521234567"
chat:resolvedUpdateTimeLast time chat was resolved1761664598
chat:lastMessage.textText of the last message"Thanks"

CRM data (after getCustomerDetails)

PathDescription
chat:crmData.nameCustomer name from CRM
chat:crmData.recordIdCRM record ID
chat:crmData.deepLinkLink to CRM record
chat:crmData.*Any field returned by the CRM adapter

Examples

messages:
- "Hi %chat:crmData.First_Name%, welcome back!"
params:
url: "https://example.com/api/chats/%chat:_id%"
params:
phone: "%chat:channelInfo.id%"
name: "%chat:title%"

state

Access the bot's runtime state — values stored during the conversation, node outputs, and session data.

%state:path%

Allowed root keys

The state provider only exposes specific root keys (all others are blocked for security):

Root keyAliasDescription
node(alias for userState)Node outputs — prompt answers, request responses, choice selections
storeValues saved via storeValue
idCurrent bot session ID
flowVersionCurrent bot flow version (identifier, version)
latestAgentUidUID of the last human agent who handled this chat
latestAgentNameDisplay name of the last human agent

Common paths

PathDescription
state:node.<node_name>.textThe text the user typed in a prompt node
state:node.<node_name>.idThe id of a selected choice
state:node.<node_name>.crm_idThe crm_id of a selected choice
state:node.<node_name>.data.<field>A data field from a selected choice
state:node.<node_name>.statusCodeHTTP status from a request node
state:node.<node_name>.responseFull HTTP response body (when keepResponse: true)
state:node.<node_name>.response.<path>Nested field from a response (e.g. .response.data.0.firstName)
state:store.<key>A value saved via storeValue
state:store.<key>.<nested>Nested field inside a stored JSON object (e.g. store.customer.type)
state:idCurrent bot session ID
state:latestAgentUidUID of the last human agent
state:latestAgentNameDisplay name of the last agent
state:flowVersion.identifierBot flow identifier
state:flowVersion.versionBot flow version number

Examples

# Use what the user typed
messages:
- "Nice to meet you, %state:node.ask_name.text%"
# Use a stored value
params:
treatmentPlanId: "%state:store.planId%"
# Access nested stored JSON
messages:
- "Welcome back, %state:store.customer.firstName%!"
# Check HTTP response status
params:
input: "%state:node.start_get_costumer_details.statusCode%"
# Access nested response data (array index with .0)
params:
value: "%state:node.get_customer_details.response.data.0.firstName%"
# Access data from a choice node
messages:
- "Your branch: %state:node.choose_branch.data.name%"
- "Phone: %state:node.choose_branch.data.phone%"

previousBotSession

You can access data from the previous bot session (the session before the current one) using the previousBotSession prefix. This is useful for checking what happened in the last bot interaction — for example, whether the customer already went through a certain flow, what they selected, or which agent handled them.

%state:previousBotSession.<same paths as above>%

The same root keys are available: node, store, id, flowVersion, latestAgentUid, latestAgentName.

PathDescription
state:previousBotSession.idPrevious bot session ID
state:previousBotSession.node.<node_name>.textA prompt answer from the previous session
state:previousBotSession.store.<key>A stored value from the previous session
state:previousBotSession.latestAgentUidLast agent UID from the previous session
state:previousBotSession.latestAgentNameLast agent name from the previous session
state:previousBotSession.flowVersion.identifierWhich bot flow ran in the previous session

Examples

# Check if the customer had an accountId stored in the previous session
params:
input: "%state:previousBotSession.store.accountId%"
# Check what the customer chose last time
params:
expression: "prevChoice == 'existing'"
prevChoice: "%state:previousBotSession.node.ask_if_customer.text%"
# Get the language from the previous session
params:
input: "%state:previousBotSession.store.language%"
cases:
hebrew: greet_hebrew
english: greet_english
tip

previousBotSession is populated when a bot session ends (handoff or resolved). It contains the full state from the session that just ended. If the customer has never been through the bot before, it will be empty/undefined.

danger

state:previousBotSession (with no subkey) returns undefined. You must always access a specific field like state:previousBotSession.id or state:previousBotSession.store.someKey.


messages

Query messages from the current conversation. Two methods are available: latest and botSession. Both always return an array — even for a single message, you must use .0 to access the first element.

Methods

MethodDescription
messages:latest(...)Get the most recent messages from the entire conversation
messages:botSession(...)Get all messages from a specific bot session

messages:latest

%messages:latest(count, order, direction, type)%

Arguments

ArgumentRequiredDefaultDescriptionValues
countYesNumber of messages to return (1–1000)Any integer
orderNo-1Sort order1 = ascending (oldest first), -1 = descending (newest first)
directionNo"any"Filter by direction"in" = incoming only, "out" = outgoing only, "any" = both
typeNoFilter by message content type"text", "media", "postback", "contacts", "location", "buttons", "list", "special"

messages:botSession

Returns all messages that belong to a specific bot session. Useful for getting only the messages exchanged during the current (or previous) bot flow run, ignoring older conversation history.

%messages:botSession%
%messages:botSession("sessionId")%

Arguments

ArgumentRequiredDefaultDescription
sessionIdNoCurrent or previous bot session IDThe bot session ID to fetch messages for

When no sessionId is provided, it defaults to the current bot session ID (botState.id). If that's not available, it falls back to the previous bot session ID (previousBotSession.id).

Returns messages sorted by timestamp (newest first). System messages are excluded.

Examples

# Get all messages from the current bot session
value: "%messages:botSession%"
# Store current session messages and extract text
value: '%messages:botSession|column("text")|join("\n")%'
No nested data injection

You cannot pass a %...% expression as an argument inside another %...%. For example, %messages:botSession("%state:previousBotSession.id%")% will not work. When no argument is provided, botSession defaults to the current or previous bot session ID automatically, which covers most use cases.

Return value — always an array

Both messages:latest(...) and messages:botSession(...) always return an array of message objects, even when only 1 message matches. This means:

  • To access a field on a single message, you must index into the array first
  • After storing the result with storeValue, access fields using .0.fieldName for the first element
# WRONG — this gives you the array, not the text
value: "%messages:latest(1,-1,"in")%.text"

# CORRECT — index with .0 to get the first message's text
value: "%state:store.pastMessages.0.text%"

Message object fields

Each message in the array is a full message object. The commonly used fields are:

FieldTypeDescription
_idstringUnique message ID
textstringMessage body text
typestringContent type: "text", "media", "postback", "contacts", "location", "buttons", "list", "special"
directionstring"incoming" or "outgoing"
timestampnumberWhen the message was created (epoch ms)
agentstringWho sent it: "Bot" or an agent UID
statusnumberDelivery state: 0=Sent, 1=Accepted, 2=Delivered, 3=Seen, 4=Failed
parent_chatstringChat ID this message belongs to
postbackobjectSelected button/list item: { payload, title } (only when type: "postback")
specialobjectTemplate/broadcast data (only when type: "special")
mediaarrayMedia attachments (only when type: "media") — each has mediaType, fileId, filename, caption
botSessionIdstringBot session ID tied to this message
metadataobjectExtra metadata — includes botMsgInfo (which bot node generated the message), triggeredBot, etc.

Accessing fields after storing

A common pattern is to store messages with storeValue, then access individual fields via the stored array:

  store_past_messages:
type: func
func_type: system
func_id: storeValue
params:
key: "pastMessages"
value: '%messages:latest(20,1,"in")%'
on_complete: next_step

%state:store.pastMessages.0._id% accesses the _id field of the first (oldest, since order is 1) message in the stored array. The .0 is the array index.


Using with transformers

Since the result is an array, you'll typically chain array transformers to extract what you need:

Extract a single field from each message with column

# Get just the text of the last 10 incoming messages
value: '%messages:latest(10,-1,"in")|column("text")%'

Combine with join for a flat string

# 10 latest incoming messages as newline-separated text
value: '%messages:latest(10,-1,"in")|column("text")|join("\n")%'

Get postback payloads

# Get the payload of the last incoming postback (button click)
value: '%messages:latest(1,1,"in","postback")|column("postback.payload")|join("\n")%'

Get message IDs

# Store the ID of the last outgoing message
value: '%messages:latest(1,-1,"out")|column("_id")|join("\n")%'

Extract the special field (e.g., Facebook/Instagram referral)

special: '%messages:latest(1,-1,"in")|column("special")%'

Format a conversation log with hbTpl (Handlebars template)

This is the recommended way to build a custom conversation log (compared to the %MESSAGES% shortcut in sendEmail). You can often put the same expression on a sendEmail content line; use storeValue first if the template is easier to maintain in state.

  store_messages:
type: func
func_type: system
func_id: storeValue
params:
key: "messages"
value: |
%messages:latest(12,1,"any","text")|hbTpl("
{{#each .}}
[{{date timestamp}}] {{#when direction 'eq' 'incoming'}}{{provide 'chat' 'title'}}{{else}}{{agent}}{{/when}}:
{{text}}

{{/each}}
")%
on_complete: send_email_with_messages

Common patterns

Check if a message came from a Facebook/Instagram ad

  check_if_from_ad:
type: func
func_type: system
func_id: matchExpression
params:
expression: 'not empty(special.0.facebook.referral)'
special: '%messages:latest(1,-1,"in")|column("special")%'
on_complete: store_social_source
on_failure: regular_start

Check if this is the user's very first message ever

Use %state:previousBotSession.id% — if it exists, the user has interacted with the bot before:

  check_returning_user:
type: func
func_type: system
func_id: matchExpression
params:
expression: 'exists(prevSession)'
prevSession: "%state:previousBotSession.id%"
on_complete: returning_user
on_failure: first_time_user

Store the last outgoing message (for template tracking)

  store_last_outgoing:
type: func
func_type: system
func_id: storeValue
params:
key: "lastOutMsg"
value: '%messages:latest(1,-1,"out")%'
on_complete: next_step
danger

messages:latest(...) always returns an array. Even messages:latest(1,...) returns an array with one element. To access a field on the single message, you must either:

  • Use |column("fieldName") to extract that field from each element, or
  • Store the result and access it as %state:store.key.0.fieldName% (.0 = first element)
tip

The type filter is optional but recommended. Use "text" to ignore media/postback messages, or "postback" to specifically get button-click responses.


time

Access the current date/time or format a given date. Supports arithmetic operations (add/subtract time), custom output formats, and timezone conversion. Powered by Luxon.

Base keys

There are two base keys:

KeyDescriptionArguments
nowCurrent date/time(format, timezone) — both optional
dateA specific date you provide(dateString, format, timezone) — dateString required

Defaults — when omitted, format defaults to dd-MM-yyyy HH:mm:ss and timezone defaults to utc.

%time:now%
%time:now("format")%
%time:now("format","timezone")%
%time:date("dateString")%
%time:date("dateString","format","timezone")%

Arithmetic operations

You can add or subtract time directly in the key using + or - followed by a number and a unit. Multiple operations can be chained.

UnitMeaningExample
yYears+1y, -2y
MMonths+3M, -1M
wWeeks+2w, -1w
dDays+7d, -3d
hHours+5h, -12h
mMinutes+30m, -15m
sSeconds+45s, -10s

Arithmetic works on both now and date:

%time:now+3d%                      # 3 days from now
%time:now-2h% # 2 hours ago
%time:now+1y-3M+15d% # 1 year, minus 3 months, plus 15 days from now
%time:date+1w("2025-06-01T10:00:00Z")% # given date + 1 week
danger

Note the uppercase M for months vs lowercase m for minutes. +3M = 3 months, +3m = 3 minutes.


Format tokens

The format string uses Luxon formatting tokens. There is also one special keyword: iso.

Common tokens

TokenOutputExample
yyyy4-digit year2026
yy2-digit year26
MMMonth (zero-padded)03
MMMMFull month nameMarch
MMMShort month nameMar
ddDay of month (zero-padded)18
dDay of month8
EEEEFull weekday nameWednesday
EEEShort weekday nameWed
HHHour 24h (zero-padded)14
hhHour 12h (zero-padded)02
mmMinutes (zero-padded)05
ssSeconds (zero-padded)09
aAM / PMPM
xUnix timestamp (milliseconds)1742313600000
XUnix timestamp (seconds)1742313600

Special format

ValueOutput
isoFull ISO 8601 string, e.g. 2026-03-18T14:05:09.000+02:00

If no format is provided, the default is dd-MM-yyyy HH:mm:ss → e.g. 18-03-2026 14:05:09.


Timezones

The second (or third for date) argument sets the timezone. Any IANA timezone is supported, plus one shorthand:

ValueTimezone
utcUTC (default)
istIsrael Standard Time (Asia/Jerusalem)
America/New_YorkUS Eastern
Europe/LondonUK
Any IANA namee.g. Asia/Tokyo, Europe/Berlin, etc.

Examples

Current time with default format (UTC)

value: "%time:now%"
# → "18-03-2026 12:05:09"

Current time in Israel timezone

value: '%time:now("dd-MM-yyyy HH:mm:ss","ist")%'
# → "18-03-2026 14:05:09"

Current date only (Israel)

value: '%time:now("dd/MM/yyyy","ist")%'
# → "18/03/2026"

Current time in ISO format

value: '%time:now("iso","ist")%'
# → "2026-03-18T14:05:09.000+02:00"

Unix timestamp in milliseconds

value: '%time:now("x")%'
# → "1742313909000"

Unix timestamp in seconds (as integer)

value: '%time:now("X")|parseInt%'
# → 1742313909

5 days ago as unix ms timestamp

value: '%time:now-5d("x")|parseInt%'

7 days ago as unix seconds

value: '%time:now-7d("X")|parseInt%'

1 hour from now in Israel time

value: '%time:now+1h("HH:mm","ist")%'
# → "15:05"

Tomorrow's date

value: '%time:now+1d("dd/MM/yyyy","ist")%'
# → "19/03/2026"

Complex arithmetic: 1 year minus 3 months plus 15 days

value: '%time:now+1y-3M+15d("dd-MM-yyyy","ist")%'

Format a specific date string

value: '%time:date("2025-06-15T10:30:00Z","dd/MM/yyyy HH:mm","ist")%'
# → "15/06/2025 13:30"

Format a date from an API response

To format a date stored in state or returned from an API, use the formatDate transformer instead:

value: '%state:node.get_appointment.response.date|formatDate("dd/MM/yyyy HH:mm","ist")%'
No nested data injection

You cannot pass a %...% expression as an argument inside another %...%. For example, %time:date("%state:store.myDate%")% will not work. Use time:date only with hardcoded date strings, and use the formatDate transformer to format dynamic dates from state or API responses.

Year and month name

value: '%time:now("MMMM yyyy","ist")%'
# → "March 2026"

Weekday name

value: '%time:now("EEEE","ist")%'
# → "Wednesday"
tip

When using time in a storeValue or request param that expects a number (e.g., a unix timestamp), pipe it through |parseInt to convert the string result to an integer.

tip

The ist timezone shorthand is a convenience for Israel Standard Time (Asia/Jerusalem). For any other timezone, use the full IANA name.